package sports

import (
	"encoding/json"
	"fmt"
	"github.com/gocolly/colly"
	"github.com/spf13/cast"
	"longmen/server/config/global"
	"longmen/server/internal/services/crawler/consts"
	"longmen/server/internal/services/crawler/protocol"
	"longmen/server/pkg/common/helper/encrypt"
	"longmen/server/pkg/common/helper/timehelper"
	"longmen/server/pkg/common/helper/util"
	"longmen/server/pkg/db/mysql/db_main"
	"longmen/server/pkg/db/mysql/models/models_main"
	"regexp"
)

var spider *douQiuSpider
var tryNum int

const (
	DouQiuDomain    = "www.qiu199.com"
	DouQiuDomainUrl = "https://www.qiu199.com"
)

type douQiuSpider struct {
	BannerSummaryCollector *colly.Collector //banner摘要
	BannerTextCollector    *colly.Collector //banner正文

	ListSummaryCollector *colly.Collector //list摘要
	ListTextCollector    *colly.Collector //list正文

	NewsCategory int
	CategoryId   int
}

func NewDouQiuSpider() *douQiuSpider {
	if spider == nil {
		consts.InitDqtyMap()
		spider = &douQiuSpider{
			BannerSummaryCollector: SpiderService.NewCollector(DouQiuDomain, DouQiuDomainUrl),
			BannerTextCollector:    SpiderService.NewCollector(DouQiuDomain, DouQiuDomainUrl),
			ListSummaryCollector:   SpiderService.NewCollector(DouQiuDomain, DouQiuDomainUrl),
			ListTextCollector:      SpiderService.NewCollector(DouQiuDomain, DouQiuDomainUrl),
		}
	}
	return spider
}

func (s *douQiuSpider) Start() {
	go s.doBanner()
	go s.doList()

}

func (s *douQiuSpider) doBanner() error {
	s.crawlerBanner()
	s.crawlerBannerChapter()
	fullUrl := DouQiuDomainUrl + "/news?activeId=999"
	if err := s.BannerSummaryCollector.Visit(fullUrl); err != nil {
		global.Log.Errorf("启动爬取任务异常,url:%s,err:%v,重试次数:%d", fullUrl, err, tryNum)
		tryNum++
		if tryNum < 10 {
			return s.doBanner()
		} else {
			tryNum = 0
		}
		return err
	}
	s.BannerSummaryCollector.Wait()
	return nil
}

func (s *douQiuSpider) doList() error {
	s.crawlerSummaryCollector()
	s.crawlerChapterCollector()
	for categoryId, v := range consts.DqtyCategorySlice {
		global.Log.Debugf("NewsCategory:%v,CategoryId:%v", v, categoryId)
		s.NewsCategory = v
		s.CategoryId = categoryId
		if err := s.ListSummaryCollector.Visit(DouQiuDomainUrl + "/news?activeId=" + cast.ToString(s.NewsCategory)); err != nil {
			fmt.Println("启动爬取任务, 异常", err)
			return err
		}
	}
	s.ListSummaryCollector.Wait()
	return nil
}

// banner
func (s *douQiuSpider) crawlerBanner() {
	s.BannerSummaryCollector.OnRequest(func(r *colly.Request) {
		fmt.Println("Visiting", r.URL.String())
	})
	s.BannerSummaryCollector.OnResponse(func(r *colly.Response) {
		global.Log.Debugf("r:%v", r.StatusCode)
	})

	//异步获取bannerlist
	s.BannerSummaryCollector.OnResponse(func(r *colly.Response) {
		var pprops MainProps
		reg := regexp.MustCompile("{\"props\":+.*}")
		jj := reg.FindAllString(string(r.Body), -1)
		err := json.Unmarshal([]byte(jj[0]), &pprops)
		// 创建上下文对象
		ctx := colly.NewContext()
		if err == nil {
			for _, v := range pprops.Props.PageProps.BannerList {
				summary := &Summary{}
				summary.Title = v.Title
				summary.Pic = v.Img
				global.Log.Debugf("图片地址是:%s", v.Img)
				ctx.Put("summary", summary)
				chapterUrl := DouQiuDomainUrl + "/news/" + v.Link
				global.Log.Debugf("Title:%s,chapterUrl:%s", summary.Title, chapterUrl)
				if err := s.BannerTextCollector.Request("GET", chapterUrl, nil, ctx, nil); err != nil {
					fmt.Println("内容页爬取异常", chapterUrl, err)
					return
				}
			}

		}
	})
}

// banner内容
func (s *douQiuSpider) crawlerBannerChapter() {
	//异步获取内容
	s.BannerTextCollector.OnResponse(func(r *colly.Response) {
		summaryCtx := r.Ctx.GetAny("summary").(*Summary)
		if summaryCtx == nil {
			global.Log.Errorf("summary empty")
			return
		}
		var pprops MainProps
		reg := regexp.MustCompile("{\"props\":+.*}")
		jj := reg.FindAllString(string(r.Body), -1)
		err := json.Unmarshal([]byte(jj[0]), &pprops)
		if err == nil {
			news := pprops.Props.PageProps.NewsDetail
			if news.News != nil {
				md5hash := encrypt.Md5(news.News.Title)
				if _, err := db_main.GetNewsByMd5hash(md5hash); err == nil {
					global.Log.Error("轮播图新闻重复")
					return
				}
				publishTime := timehelper.StrToUnix(news.News.PublishTime)
				err = db_main.InsertNews(&models_main.News{Title: summaryCtx.Title, PublishTime: publishTime, Content: news.News.Content, Img: summaryCtx.Pic, Md5hash: md5hash, CategoryId: 1, IsBanner: 1, Status: 1, IsHot: 1, CategorySite: 1})
				if err != nil {
					global.Log.Error("InsertNews err:%v", err)
				}
			}
		}
	})
}

// 新闻列表
func (s *douQiuSpider) crawlerSummaryCollector() {
	//异步获取新闻列表
	s.ListSummaryCollector.OnResponse(func(r *colly.Response) {
		var pprops protocol.MainProps
		reg := regexp.MustCompile("{\"props\":+.*}")
		jj := reg.FindAllString(string(r.Body), -1)
		err := json.Unmarshal([]byte(jj[0]), &pprops)
		// 创建上下文对象
		ctx := colly.NewContext()
		if err == nil {
			for _, v := range pprops.Props.PageProps.WebNewsCategoryIdList.NewsList {
				chapterUrl := DouQiuDomainUrl + "/news/" + v.Id
				global.Log.Debugf("Title:%s,chapterUrl:%s", v.Title, chapterUrl)
				if err = s.ListTextCollector.Request("GET", chapterUrl, nil, ctx, nil); err != nil {
					fmt.Println("内容页爬取异常", chapterUrl, err)
					return
				}
			}
		}
	})
}

// 新闻详情
func (s *douQiuSpider) crawlerChapterCollector() {
	//异步获取内容
	s.ListTextCollector.OnResponse(func(r *colly.Response) {
		var pprops protocol.MainProps
		reg := regexp.MustCompile("{\"props\":+.*}")
		jj := reg.FindAllString(string(r.Body), -1)
		err := json.Unmarshal([]byte(jj[0]), &pprops)
		if err == nil {
			news := pprops.Props.PageProps.NewsDetail

			if news.News != nil {
				md5hash := encrypt.Md5(news.News.Title)
				if _, err := db_main.GetNewsByMd5hash(md5hash); err == nil {
					global.Log.Error("新闻名重复")
					return
				}
				isHost := 0
				if getDbNewsCategoryId(s.NewsCategory) == 1 {
					isHost = 1
				}
				publishTime := timehelper.StrToUnix(news.News.PublishTime)
				randHits := util.MaxMinRand(500, 2000)
				err = db_main.InsertNews(&models_main.News{Title: news.News.Title, PublishTime: publishTime, Content: news.News.Content, Img: news.News.Img, Md5hash: md5hash, CategoryId: getDbNewsCategoryId(s.NewsCategory), IsBanner: 0, Status: 1, IsHot: isHost, CategorySite: s.CategoryId, RandHits: randHits})
				if err != nil {
					global.Log.Error("InsertNews err:%v", err)
				}
			}
		}
	})
}

// 入库新闻分类id 1.热门 2.足球 3.篮球  4.综合 12.电竞
func getDbNewsCategoryId(id int) int {
	switch id {
	case 2, 3, 5, 10003, 10002, 10001, 10004, 10005:
		return 2
	case 8, 10007:
		return 3
	case 9999:
		return 1
	case 6:
		return 12
	case 10009:
		return 4
	}
	return id
}

type MainProps struct {
	Props Props `json:"props"`
}

type Props struct {
	PageProps PageProps `json:"pageProps"`
}

type PageProps struct {
	BannerList []BannerList `json:"bannerList"`
	NewsDetail struct {
		News *News `json:"news"`
	} `json:"newsDetail"`
}

type BannerList struct {
	Link  string `json:"link"`
	Img   string `json:"img"`
	Title string `json:"title"`
}

type Summary struct {
	Title       string `json:"title"`
	Content     int64  `json:"content"`
	Pic         string `json:"imgUrl"`
	CreatedDate string `json:"createdDate"`
}

type News struct {
	Content     string `json:"content"`
	Img         string `json:"imgUrl"`
	Title       string `json:"title"`
	PublishTime string `json:"createdDate"`
}
